package com.mcxx.modules.extremepoverty.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.mcxx.common.exception.BizException;
import com.mcxx.constant.MQConstant;
import com.mcxx.modules.extremepoverty.service.ExSalvationNoticeBoardService;
import com.mcxx.modules.base.service.read.RuleEngineReadService;
import com.mcxx.modules.miniSalvation.order.dto.*;
import com.mcxx.modules.miniSalvation.order.entity.NoticeBoardDetailEntity;
import com.mcxx.modules.miniSalvation.order.entity.OrderEntity;
import com.mcxx.modules.miniSalvation.order.param.OrderListSearchParam;
import com.mcxx.modules.miniSalvation.order.service.read.NoticeBoardDetailReadService;
import com.mcxx.modules.miniSalvation.order.service.read.NoticeBoardReadService;
import com.mcxx.modules.miniSalvation.order.service.read.OrderCertReadService;
import com.mcxx.modules.miniSalvation.order.service.read.OrderReadService;
import com.mcxx.modules.miniSalvation.order.service.write.NoticeBoardDetailWriteService;
import com.mcxx.modules.miniSalvation.order.service.write.NoticeBoardWriteService;
import com.mcxx.modules.miniSalvation.order.service.write.OrderWriteService;
import com.mcxx.modules.system.dto.MQMessageDTO;
import com.mcxx.util.*;
import com.yinhai.ta404.core.security.vo.UserAccountVo;
import com.yinhai.ta404.core.service.BaseService;
import com.yinhai.ta404.core.transaction.annotation.TaTransactional;
import org.apache.commons.collections4.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import com.mcxx.redis.client.RedisClusterUtils;

import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;


@Service
@TaTransactional
public class ExSalvationNoticeBoardServiceImpl extends BaseService implements ExSalvationNoticeBoardService {

    @Autowired
    private NoticeBoardWriteService noticeBoardWriteService;
    @Autowired
    private NoticeBoardReadService noticeBoardReadService;
    @Autowired
    private NoticeBoardDetailWriteService noticeBoardDetailWriteService;
    @Autowired
    private NoticeBoardDetailReadService noticeBoardDetailReadService;
    @Autowired
    private OrderReadService orderReadService;
    @Autowired
    private OrderWriteService orderWriteService;
    @Autowired
    private OrderCertReadService orderCertReadService;
    @Autowired
    private RuleEngineReadService ruleEngineReadService;
    @Autowired
    private RedisClusterUtils redisClusterUtils;
    @Autowired
    private RabbitTemplate rabbitTemplate;

    private final static Logger log = LoggerFactory.getLogger(ExSalvationNoticeBoardServiceImpl.class);

    @Override
    public boolean changeDtoToEntity(NoticeBoardDTO noticeBoard, UserAccountVo userAccountVo){
        try{

            String batchNo = BatchNoUtil.getBatch(Constant.BusiCode.NOTICE_BOARD_BATCH,  noticeBoard.getAreaCode());
            noticeBoard.setBatchNo(batchNo);
            boolean rst = noticeBoardWriteService.addNoticeBoard(noticeBoard, userAccountVo);
            if(!rst){
                log.info("创建公示addNoticeBoard结果为{}",rst);
                throw new BizException("-1", "创建公示异常");
            }

            String redisKey = userAccountVo.getAreaCode()+noticeBoard.getBatchId()+noticeBoard.getStandType();
            if(Constant.UserLevel.COUNTY.equals(userAccountVo.getAreaLevel())){

                String s = setAreaCodeByLevel(noticeBoard.getAreaCode(), 4);
                redisKey = s+noticeBoard.getBatchId()+noticeBoard.getStandType();
            }
            List<NoticeBoardDetailEntity> noticeBoardDetailList = new ArrayList<>();
            Map<String, OrderListForChoiceDTO> map = redisClusterUtils.hmget(redisKey);

            if(null != map){
                map.values().forEach(value -> {
                    OrderListForChoiceDTO dto = value;
                    NoticeBoardDetailEntity entity = new NoticeBoardDetailEntity();
                    BeanUtils.copyProperties(dto, entity);
                    entity.setBatchId(noticeBoard.getBatchId());
                    entity.setId(Constant.getUUID());
                    entity.setUserAreaLevel(userAccountVo.getAreaLevel());
                    entity.setIsObjection("1");
                    entity.setCheckResult("1");
                    String saveDate = dto.getStartMonth();
                    SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy-MM-dd");
                    Date date = DateUtil.str2Date(saveDate, sdf2);
                    entity.setSaveDate(date);
                    entity.setRemark("");
                    noticeBoardDetailList.add(entity);
                });
            }else{
                log.info("创建公示:map == null");
                throw new BizException("-1", "创建公示异常");
            }
            if(CollectionUtils.isNotEmpty(noticeBoardDetailList)){
                this.saveBatchObject(noticeBoardDetailList, userAccountVo, false);

                this.createChildNotice(noticeBoard, userAccountVo);
                return true;
            }else {
                log.info("创建公示:noticeBoardDetailList为空");
                throw new BizException("-1", "创建公示异常");
            }
        }catch (Exception e){
            log.error("创建公示出现异常:"+e);
            throw e;
        }
    }


    public static String setAreaCodeByLevel(String areaCode, Integer areaCodeLevel){
        if(null == areaCodeLevel) {
            return areaCode;
        }
        if(areaCodeLevel == 1){

            return areaCode.substring(0,2);
        }
        if(areaCodeLevel == 2){

            return areaCode.substring(0,4);
        }
        if(areaCodeLevel == 3){

            return areaCode.substring(0,6);
        }
        if(areaCodeLevel == 4){

            return areaCode.substring(0,9);
        }
        if(areaCodeLevel == 5){

            return areaCode;
        }

        return areaCode;
    }


    @Override
    public Boolean deleteRedisKey(String batchId){
        if(StringUtils.isEmpty(batchId)){
            return true;
        }
        int res = 0;
        Set<String> strings = redisClusterUtils.hasKeys(batchId);
        if(CollectionUtils.isNotEmpty(strings)){
            for (String s : strings){
                res += redisClusterUtils.del(s);
            }
        }
        if(res > 0){
            return true;
        }
        return false;
    }


    @Override
    public int saveBatchObject(List<NoticeBoardDetailEntity> noticeBoardDetailList, UserAccountVo userAccountVo,boolean isChildren){

        List<String> orderIdList = new ArrayList<>();
        for (NoticeBoardDetailEntity entity: noticeBoardDetailList) {
            orderIdList.add(entity.getOrderId());
            entity.setUserAreaLevel(userAccountVo.getAreaLevel());
            entity.setId(Constant.getUUID());
        }


        int rst = noticeBoardDetailWriteService.insertObject(noticeBoardDetailList);
        if(rst <= 0){
            throw new BizException("-1", "将业务添加到公示异常");
        }


        if(!isChildren){
            this.updateOrderStateForSaveObject(orderIdList, userAccountVo);
        }
        return 1;
    }


    public void updateOrderStateForSaveObject(List<String> orderIdList, UserAccountVo userAccountVo){
        List<OrderStateVerifyDTO> orderStateVerifyDTOList = orderReadService.getBizStateReportFileList(orderIdList);

        String bizStateType = Constant.UserLevel.STREET.equals(userAccountVo.getAreaLevel())
                ? Constant.OrderBizStateType.WAIT_NOTICE
                : Constant.OrderBizStateType.WAIT_NOTICE_COUNTRY;

        orderStateVerifyDTOList.forEach(orderStateVerifyDTO -> {
            ruleEngineReadService.getBizStateRuleThrow(bizStateType, orderStateVerifyDTO, userAccountVo);

            OrderEntity updateOrderEntity = new OrderEntity();
            updateOrderEntity.setOrderId(orderStateVerifyDTO.getOrderId());
            updateOrderEntity.setVersion(orderStateVerifyDTO.getVersion());
            updateOrderEntity.setBizState(orderStateVerifyDTO.getNextBizState());
            updateOrderEntity.setUpdateTime(new Date());
            updateOrderEntity.setUpdateBy(userAccountVo.getUserId());
            orderWriteService.updateIgnoreNull(updateOrderEntity);

        });
    }


    @Override
    public Map<String, List<String>> confirmBatch(List<String> batchNoList, UserAccountVo userAccountVo){

        List<String> stateList = new ArrayList<String>(){{add(Constant.NoticeBoardState.WAIT); add(Constant.NoticeBoardState.REVOKE);}};
        Map<String, List<String>> rstMap = noticeBoardReadService.getBatchNoByStateStartDate(batchNoList, stateList, "Y");
        if(rstMap.containsKey("yesOperation") == false){
            return rstMap;
        }


        rstMap.putAll(noticeBoardDetailReadService.getNoByNoAndFamilyNums(rstMap.get("yesOperation")));
        if(rstMap.containsKey("yesObject") == false){
            return rstMap;
        }


        int rst = noticeBoardWriteService.updateStatusByBatchNos(rstMap.get("yesObject"), Constant.NoticeBoardState.ING,
                                                            null);
        if(rst <= 0){

            rstMap.put("fail", rstMap.get("yesObject"));
            return rstMap;
        }


        this.updateOrderStateByConfirm(batchNoList, userAccountVo);

        rstMap.put("success", rstMap.get("yesObject"));
        return rstMap;
    }


    public void updateOrderStateByConfirm(List<String> batchNoList, UserAccountVo userAccountVo){

        String bizStateType = Constant.UserLevel.STREET.equals(userAccountVo.getAreaLevel())
                ? Constant.OrderBizStateType.WAIT_NOTICE_CONFIRM
                : Constant.OrderBizStateType.WAIT_NOTICE_CONFIRM_COUNTRY;

        this.updateOrderState(batchNoList, bizStateType, userAccountVo);
    }


    public void updateOrderState(List<String> batchNoList, String bizStateType, UserAccountVo userAccountVo){
        List<OrderStateVerifyDTO> orderStateVerifyDTOList = orderReadService.getBizStateReportFileNotice(batchNoList, "BAX21");
        orderStateVerifyDTOList.forEach(orderStateVerifyDTO -> {
            ruleEngineReadService.getBizStateRuleThrow(bizStateType, orderStateVerifyDTO, userAccountVo);

            OrderEntity updateOrderEntity = new OrderEntity();
            updateOrderEntity.setOrderId(orderStateVerifyDTO.getOrderId());
            updateOrderEntity.setVersion(orderStateVerifyDTO.getVersion());
            updateOrderEntity.setBizState(orderStateVerifyDTO.getNextBizState());
            updateOrderEntity.setUpdateTime(new Date());
            updateOrderEntity.setUpdateBy(userAccountVo.getUserId());
            if(!CommonUtil.invalidArgs(orderStateVerifyDTO.getNextState())){
                updateOrderEntity.setState(orderStateVerifyDTO.getNextState());
            }
            orderWriteService.updateIgnoreNull(updateOrderEntity);
        });
    }



    @Override
    public Map<String, List<String>> deleteBatch(List<String> batchNoList, UserAccountVo userAccountVo){

        List<String> stateList = new ArrayList<String>(){{add(Constant.NoticeBoardState.WAIT); add(Constant.NoticeBoardState.REVOKE);}};
        Map<String, List<String>> rstMap = noticeBoardReadService.getBatchNoByStateStartDate(batchNoList, stateList, "N");
        if(rstMap.containsKey("yesOperation") == false){

            return rstMap;
        }


        this.updateOrderStateByDelete(rstMap.get("yesOperation"), userAccountVo);


        int rst = noticeBoardWriteService.deleteBatch(rstMap.get("yesOperation"));
        if(rst <= 0){
            rstMap.put("success", rstMap.get("yesOperation"));
        }


        rstMap.put("success", rstMap.get("yesOperation"));
        return rstMap;
    }


    public void updateOrderStateByDelete(List<String> batchNoList, UserAccountVo userAccountVo){

        String bizStateType = Constant.UserLevel.STREET.equals(userAccountVo.getAreaLevel())
                ? Constant.OrderBizStateType.DEL_NOTICE
                : Constant.OrderBizStateType.DEL_NOTICE_COUNTRY;

        this.updateOrderState(batchNoList, bizStateType, userAccountVo);
    }


    @Override
    public Map<String, List<String>> finishBatch(List<NoticeBoardDetailEntity> changeData,
                                                 String batchNo,
                                                 String batchId,
                                                 String finishRemark,
                                                 UserAccountVo userAccountVo){


        Map<String, List<String>> rstMap = noticeBoardReadService.getBatchNoByStateStartDate(
                                            new ArrayList<String>(){{add(batchNo);}}, Constant.NoticeBoardState.ING);
        if(rstMap.containsKey("yesOperation") == false){
            return rstMap;
        }


        this.verifyNoticeCertNum(rstMap,userAccountVo.getAreaLevel(),batchId);
        if(rstMap.get("yesOperation").size() == 0){

            return rstMap;
        }
        int rst = noticeBoardWriteService.updateStatusByBatchNos(rstMap.get("yesOperation"), Constant.NoticeBoardState.COMPLETE, finishRemark);
        if(rst <= 0){

            rstMap.put("fail", rstMap.get("yesOperation"));
            return rstMap;
        }
        if(CollectionUtils.isNotEmpty(changeData)){
            int i = noticeBoardDetailWriteService.updateBatchId(changeData);
            if(rst <= 0){

                rstMap.put("fail", rstMap.get("yesOperation"));
                return rstMap;
            }
        }

        this.updateOrderStateByFinish(rstMap.get("yesOperation"), userAccountVo);


        rstMap.put("success", rstMap.get("yesOperation"));


        return rstMap;
    }


    public void updateOrderStateByFinish(List<String> batchNoList, UserAccountVo userAccountVo){

        String bizStateType = Constant.UserLevel.STREET.equals(userAccountVo.getAreaLevel())
                ? Constant.OrderBizStateType.COMPLETE_NOTICE
                : Constant.OrderBizStateType.COMPLETE_NOTICE_COUNTRY;

        this.updateOrderState(batchNoList, bizStateType, userAccountVo);
    }


    private void verifyNoticeCertNum(Map<String, List<String>> batchNoMap,String userLevel,String batchId){
        List<String> yesOperationBatchNoList = batchNoMap.get("yesOperation");
        List<String> noCertList = new ArrayList<>();
        List<NoticeBoardDTO> noticeBoardDTOList = new ArrayList<>();
        if(Constant.UserLevel.STREET.equals(userLevel)){
            noticeBoardDTOList = orderCertReadService.cntNoticesCertNum(yesOperationBatchNoList);
        }else{

            noticeBoardDTOList = orderCertReadService.cntNoticeIdCertNum(batchId);
        }
        yesOperationBatchNoList = new ArrayList<>();
        if(CollectionUtils.isEmpty(noticeBoardDTOList)){
            noCertList.addAll(batchNoMap.get("yesOperation"));
        }else{
            for (NoticeBoardDTO noticeBoardDTO: noticeBoardDTOList){
                if(noticeBoardDTO.getCertNum() > 0){

                    yesOperationBatchNoList.add(noticeBoardDTO.getBatchNo());
                }else{

                    noCertList.add(noticeBoardDTO.getBatchNo());
                    throw new BizException("-1", noticeBoardDTO.getAreaCodeName()+"没有上传公示照片,不能结束公示");
                }
            }
        }
        batchNoMap.put("yesOperation", yesOperationBatchNoList);
        batchNoMap.put("noCert", noCertList);
    }


    @Override
    public Map<String, Object> printNoticeBoardTown(OrderListSearchParam param){
        Map<String, Object> rstMap = new HashMap<>();

        NoticeBoardDTO noticeBoard = noticeBoardReadService.queryByBatchId(param.getBatchId());

        Calendar calendar = Calendar.getInstance();
        calendar.setTime(noticeBoard.getStartDate());
        calendar.add(Calendar.DAY_OF_YEAR,6);
        noticeBoard.setEndDate(calendar.getTime());

        noticeBoard.setTimeLimit("7");

        rstMap.put("noticeBoard", noticeBoard);



        param.setTableOrder("BAX21");
        param.setTableFamily("BAF01");
        List<NoticeBoardDetailDTO> noticeBoardDetailList = noticeBoardDetailReadService.queryTownMiniObjectByBatchId(param);

        List<NoticeBoardDetailDTO> checkYesList = noticeBoardDetailList.stream().filter((o-> Constant.CheckResult.YES.equals(o.getCheckResult()))).collect(Collectors.toList());

        List<NoticeBoardDetailDTO> checkNoList = noticeBoardDetailList.stream().filter((o-> Constant.CheckResult.NO.equals(o.getCheckResult()))).collect(Collectors.toList());
        rstMap.put("checkYesList", checkYesList);
        rstMap.put("checkNoList",checkNoList);
        NoticeBoardDetailDTO underAge =  noticeBoardDetailReadService.queryUnfinishUnderAgeFamily(param);
        rstMap.put("underAgeFamilyNumber",underAge.getFamilyNumber());
        rstMap.put("underAgeFamilyCount",underAge.getFamilyCount());

        return rstMap;
    }


    @Override
    public Map<String, Object> printNoticeBoardCounty(OrderListSearchParam param){
        Map<String, Object> rstMap = new HashMap<>();

        NoticeBoardDTO noticeBoard = noticeBoardReadService.queryByBatchId(param.getBatchId());

        Calendar calendar = Calendar.getInstance();
        calendar.setTime(noticeBoard.getStartDate());
        calendar.add(Calendar.DAY_OF_YEAR,6);
        noticeBoard.setEndDate(calendar.getTime());

        noticeBoard.setTimeLimit("7");
        rstMap.put("noticeBoard", noticeBoard);

        List<NoticeBoardDetailDTO> noticeBoardDetailList = noticeBoardDetailReadService.queryCountyMiniObjectByBatchId(param);
        rstMap.put("noticeBoardDetailList", noticeBoardDetailList);
        NoticeBoardDetailDTO underAge =  noticeBoardDetailReadService.queryUnfinishUnderAgeFamily(param);
        rstMap.put("underAgeFamilyNumber",underAge.getFamilyNumber());
        rstMap.put("underAgeFamilyCount",underAge.getFamilyCount());

        return rstMap;
    }


    @Override
    public void createChildNotice(NoticeBoardDTO noticeBoard, UserAccountVo userAccountVo){
        if(Constant.UserLevel.COUNTY.equals(userAccountVo.getAreaLevel())
                && !Constant.BusinessCode.LINSHI.equals(noticeBoard.getBusinessType())){

            List<NoticeBoardDetailEntity> detailLists = noticeBoardDetailReadService.queryAreaByBatchId(noticeBoard.getBatchId());

            Map<String, List<NoticeBoardDetailEntity>> areaMapList = detailLists.stream().collect(Collectors.groupingBy(NoticeBoardDetailEntity::getStreetCode));


            areaMapList.forEach((k,v)->{

                NoticeBoardDTO childDto = new NoticeBoardDTO();
                BeanUtils.copyProperties(noticeBoard,childDto);
                String batchId = Constant.getUUID();
                childDto.setParentId(childDto.getBatchId());
                childDto.setNoticeType("2");
                childDto.setAreaCode(k+"000");
                childDto.setBatchId(batchId);
                boolean rst = noticeBoardWriteService.addNoticeBoard(childDto, userAccountVo);
                if(rst){
                    List<NoticeBoardDetailEntity> detailList = new ArrayList<>();
                    for(NoticeBoardDetailEntity detail : v){
                        detail.setBatchId(batchId);
                        detailList.add(detail);
                    }
                    this.saveBatchObject(detailList, userAccountVo,true);
                }
            });
        }
    }


    @Override
    public List<NoticeBoardDTO> cntNoticeIdCertNum(String batchId){ return orderCertReadService.cntNoticeIdCertNum(batchId); }
}
